﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using Backend.Packets;

namespace GameServer.Backend.Managers
{
    internal class ChatRoom
    {
        public List<GameClient> ClientsInRoom;
        public bool Private; //Status of room.  Is it visible or not.
        public string RoomName;
        public short RoomId;
        public string RoomDescription;
        public GameClient Owner;
    }

    public class ChatManager
    {
        private List<ChatRoom> m_ChatRooms;

        private object m_SyncObject;

        private short m_nRoomIdCounter;

        public ChatManager()
        {
            m_ChatRooms = new List<ChatRoom>();
            m_SyncObject = new object();

            CreateRoom("Jeff's Room", "It's kickin in here");
        }

        /// <summary>
        /// Joins the specified chat room.
        /// </summary>
        /// <param name="Packet"></param>
        /// <param name="Client"></param>
        private void JoinRoom(ChatPacket Packet, GameClient Client)
        {
            lock (m_SyncObject)
            {
                //Lambda for finding if a client is already in the specified room.
                bool bClientInRoom = m_ChatRooms.Find(x => x.RoomName == Packet.Room).ClientsInRoom.Exists(x => x.UserName == Client.UserName);

                if (bClientInRoom)
                {
                    ChatPacket Response = new ChatPacket();
                    Response.Message = "You are already in that room.";
                    Response.Command = ChatPacket.ChatCommand.JOIN_ROOM_RESPONSE;
                    Client.Send(Response);
                    return;
                }

                m_ChatRooms.Find(x => x.RoomName == Packet.Room).ClientsInRoom.Add(Client);
            }

            SendListToRoom(Packet.Room);
        }

        private void SendToUser(string To, string Message, GameClient Client)
        {
            ChatPacket Payload = new ChatPacket();
            Payload.Command = ChatPacket.ChatCommand.MESSAGE_FROM_USER;
            Payload.From = Client.UserName;
            Payload.To = To;
            Payload.Message = Message;

            GameClient ToSendTo = GameServer.GetInstance().FindUser(To);

            //Requested client doesn't exist or is no longer logged in.
            if (ToSendTo == null)
                return;

            ToSendTo.Send(Payload);
        }

        /// <summary>
        /// Sends a message to a room.
        /// </summary>
        /// <param name="RoomId"></param>
        private void SendToRoom(string RoomName, GameClient Client, string Message)
        {
            ChatPacket Payload = new ChatPacket();
            Payload.Command = ChatPacket.ChatCommand.MESSAGE_FROM_ROOM;
            Payload.From = Client.UserName;
            Payload.Message = Message;

            lock (m_SyncObject)
                m_ChatRooms.Find(x => x.RoomName == RoomName).ClientsInRoom.ForEach(x => x.Send(Payload));
        }

        /// <summary>
        /// Updates clients in the room with a list of users.
        /// </summary>
        /// <param name="ChatRoom"></param>
        private void SendListToRoom(string ChatRoom)
        {
            string Users = String.Empty;

            lock (m_SyncObject)
            {
                m_ChatRooms.Find(x => x.RoomName == ChatRoom).ClientsInRoom.ForEach(x => Users += x.UserName + ",");

                ChatPacket Payload = new ChatPacket();
                Payload.Command = ChatPacket.ChatCommand.LIST_ROOM_RESPONSE;
                Payload.Message = Users;

                lock(m_SyncObject)
                    m_ChatRooms.Find(x => x.RoomName == ChatRoom).ClientsInRoom.ForEach(x => x.Send(Payload));
            }
        }

        /// <summary>
        /// Removes a user from all rooms.
        /// </summary>
        /// <param name="Client"></param>
        public void ClientDC(GameClient Client)
        {
            foreach (ChatRoom Room in m_ChatRooms)
            {
                for (int i = 0; i < Room.ClientsInRoom.Count; i++)
                    if (Client.UserName == Room.ClientsInRoom[i].UserName)
                    {
                        Room.ClientsInRoom.RemoveAt(i);
                        SendListToRoom(Room.RoomName); //Notify the users...
                    }
            }
        }

        private void LeaveRoom(ChatPacket Packet, GameClient Client)
        {
            m_ChatRooms.Find(x => x.RoomName == Packet.Room).ClientsInRoom.Remove(Client);
            SendListToRoom(Packet.Room);
        }

        private void CreateRoom(string Name, string Description)
        {
            ChatRoom NewRoom = new ChatRoom();

            NewRoom.ClientsInRoom = new List<GameClient>();
            NewRoom.Private = false;
            NewRoom.RoomDescription = Description;
            NewRoom.Owner = null;
            NewRoom.RoomName = Name;

            lock (m_SyncObject)
            {
                NewRoom.RoomId = m_nRoomIdCounter;
                m_ChatRooms.Add(NewRoom);
                ++m_nRoomIdCounter;
            }
        }

        /// <summary>
        /// Creates a chat room if possible.
        /// </summary>
        /// <param name="Packet"></param>
        /// <param name="Client"></param>
        /// <returns></returns>
        private bool CreateRoom(ChatPacket Packet, GameClient Client)
        {
            bool bPrivate = Packet.Private;
            string sDescription = Packet.Message;
            string sName = Packet.Room;

            if (m_ChatRooms.Exists(x => x.RoomName == sName))
            {
                ServerEventPacket Response = new ServerEventPacket();
                Response.Message = "Chat Room Already Exists.";
                Client.Send(Response);
                return false;
            }

            ChatRoom NewRoom = new ChatRoom();
            NewRoom.ClientsInRoom = new List<GameClient>();
            NewRoom.Private = bPrivate;
            NewRoom.RoomDescription = sDescription;
            NewRoom.RoomName = sName;
            NewRoom.Owner = Client;

            lock (m_SyncObject)
            {
                NewRoom.RoomId = m_nRoomIdCounter;
                m_ChatRooms.Add(NewRoom);
                m_nRoomIdCounter++;
            }

            return true;
        }

        /// <summary>
        /// Lists the public chat rooms on the server.
        /// </summary>
        /// <param name="Client"></param>
        private void ListRooms(GameClient Client)
        {
            string sRooms = String.Empty;
            ChatPacket Payload = new ChatPacket();

            foreach (ChatRoom Room in m_ChatRooms)
                if (Room.Private == false)
                    sRooms += (Room.RoomName + ",");
            Payload.Command = ChatPacket.ChatCommand.LIST_ROOMS_REPONSE;
            Payload.Message = sRooms;

            Client.Send(Payload);
        }

        public void ParsePacket(ChatPacket Packet, GameClient Client)
        {
            switch (Packet.Command)
            {
                case ChatPacket.ChatCommand.JOIN_ROOM:
                    JoinRoom(Packet, Client);
                    break;
                case ChatPacket.ChatCommand.LIST_ROOM:
                    SendListToRoom(Packet.Room);
                    break;
                case ChatPacket.ChatCommand.MESSAGE_ROOM:
                    SendToRoom(Packet.Room, Client, Packet.Message);
                    break;
                case ChatPacket.ChatCommand.MESSAGE_USER:
                    SendToUser(Packet.To, Packet.Message, Client);
                    break;
                case ChatPacket.ChatCommand.LIST_ROOMS:
                    ListRooms(Client);
                    break;
                case ChatPacket.ChatCommand.LEAVE_ROOM:
                    LeaveRoom(Packet, Client);
                    break;
            }
        }
    }
}
